<?php
/**
 * Created by PhpStorm.
 * User: Inhere
 * Date: 2015/1/28
 * Use : ...
 * File: Uri.php
 */

namespace ulue\core\router;

use Ioc;
use Ulue;
use ulue\libs\datastorage\AbstractDataOperator;
use ulue\libs\traits\TraitGetOwner;

class Uri extends AbstractDataOperator
{

    use TraitGetOwner;

    protected function storeMode()
    {
        return 'simple';
    }

    public function set($path, $value, $createNode=true)
    {
        if ( empty($value) || !is_string($value) ) {
            throw new \DInvalidArgumentException(sprintf(
                'The 2 parameter must be of type string is not empty, %s given',
                is_string($value)? $value:gettype($value)
            ));
        }

        return parent::set($path, $value, true);
    }

    public function mset(array $data)
    {
        foreach($data as $path=>$value) {
            $this->set($path, $value);
        }

        return $this;
    }

    /**
     * 创建url地址,$abs_url=false 默认产生的是相对url
     * 四种类型的 url格式: 1 PATH, 2 rewrite, 3 兼容格式, 4 传统get方式
     * e.g.
     *          ('user/login'      , 'id=12&status=1' )
     * 等同于 ( ['user','login']   , 'id=12&status=1' )
     * 等同于 ('user/login?id=12'  , 'status=1' )
     * 等同于 ('user/login'        , ['id'=>'12', 'status'=>'1'] )
     * 等同于 ('user/login?id=12'  , ['status'=>'1'] )
     *
     * RETURN:
     * 1 /index.php/user/login?id=12&status=1
     * 2 /user/login?id=12&status=1
     * 3 /index.php?r=user/login/select&id=12&status=1
     * 4 /index.php?c=user&a=login&id=12&status=1
     * @param string $route 路由请求部分 @example Blog/index/login  /Blog/cate
     * @param string $param 额外参数部分 @example id=12&status=1
     * @param bool $abs_url
     * @param bool|string $suffix
     * @param string $mode
     * @return mixed|string
     */
    public function create($route, $param='', $abs_url=false, $suffix=false, $format=null)
    {
        if (!$route) {
            return '/';
        }

        static $_route          = array();
        list($routeStr, $param) = $this->parseRouteAndParam($route, $param);

        if (!$routeStr && !$param) {
            return '/';
        }

        /**
         * @var $router Router
         */
        $router = Ioc::get('router');

        $format = Router::isUsableFormat($format) ? : $router->format;# url格式
        $key    = md5($routeStr. $param . (int)$abs_url.$suffix.$format);

        if (isset($_route[$key])) {
            return $_route[$key];
        }

        // 不要产生后缀
        if ($suffix===false) {
            $suffix = '';
        } else {
            if ( !$suffix ) {
                $suffix = $router->suffix; # 默认后缀
            }

            $suffix = '.'.trim($suffix,'. ');
        }

        $hostUrl    = $this->get('app.host');
        //$appUrl     = $this->get('app.path');
        $indexUrl   = $this->get('index.path');

        // 已经是个 可用的链接地址
        if ( $url = $this->isEnabledAddr($routeStr, $param, $abs_url) ) {
            return ($_route[$key] = $url);
        }

        $routeVar = $router->routeVar;
        $vars      = $router->getVars(true);

        // 根据url格式 产生不同形式的url字符串
        switch ($format) {
            // rewrite方式
            case Router::FORMAT_REWRITE:
                $url = '/'.$routeStr.$suffix . ( !$param ? '' : '?'.$param );
                break;
            // 兼容 方式
            case Router::FORMAT_COMPAT:
                $url = $indexUrl.'?'.$routeVar.'='.$routeStr . ( !$param ? '' : '&'.$param );
                break;
            // 传统 get参数 方式
            // case Router::FORMAT_RAW: {
            //     $routeArr   = explode('/', $routeStr);

            //     if ( Module::isModule($routeArr[0]) ) {
            //         foreach ($routeArr as $key=>$value) {
            //             $url .= $vars[$key]."=$value&";
            //         }
            //     }

            //     $url = $indexUrl.'?'. $url . $param;

            // }
                break;
            // PATH_INFO 方式
            default:
                $url = $indexUrl.'/'.$routeStr.$suffix . ( !$param ? '' : '?'.$param );
                break;
        }

        //是否产生绝对地址，默认产生相对地址
        $_route[$key] = (bool) $abs_url ? $hostUrl . $url : $url;

        return $_route[$key];
    }

    /**
     * @param $route array|string 路由请求部分
     * @example Blog/index/login  /Blog/cate blog.cate
     * 数组方式传入
     * array(
     *  'route'=>'blog/cate',
     *  'param'=>'id=12&status=1'
     * )
     * @param $param array|string 额外参数部分 @example id=12&status=1
     * @return string
     */
    private function parseRouteAndParam($route, $param)
    {
        if (isset($route['route'])) {
            $param = isset($route['param']) ? $route['param'] : '';
            $route = $route['route'];
        }

        if (is_array($route)) {
            $routeStr = implode('/',$route);
        } else {
            $routeStr = (string) $route;
        }

        if (is_array($param)) {
            $param    = http_build_query($param);
        }

        // 参数已存在 '/dev.php/site/about?aa=ffff&clear=cache', 'clear=cache'
        $route    = str_replace($param, '', $routeStr);
        $routeStr = trim($route,'?& ');

        // $routeStr 是否带有参数 'Blog/cate?id=12&status=1'
        if ( ($pos=strpos($routeStr, '?')) !== false ) {
            $hasParam  = trim( substr( $routeStr , $pos+1) ,'/& ' );
            $routeStr  = rtrim( substr( $routeStr, 0, $pos ) ,'/ ' );
            $param     = !$param ? $hasParam : $hasParam.'&'.$param;
        }
        // $routeStr == 'c=post&a=view'
        else if ( strpos($routeStr, '&') ) {
            $param    = $routeStr.'&'.$param;
            $routeStr = '';
        }

        // return ['route'=>$routeStr, 'param'=> trim($param,'&? ')];
        return [ $routeStr, trim($param,'&? ')];
    }

    /**
     * @param $routeStr
     * @param $param
     * @param $abs_url
     * @return bool|string
     */
    private function isEnabledAddr($routeStr, $param, $abs_url)
    {
        /**
         * 判断首字符 == '/'(根路径)
         * 或者
         * $routeStr==''(使用默认路由或以默认方式传入路由 e.g. 'c=post&a=view')
         */
        if ( (substr($routeStr, 0,1) == '/') || !$routeStr) {
            return ( (bool)$abs_url ? $this->get('app.host') : '' ) . $routeStr.'?' . $param;
        }

        // 已经是个链接
        if ( UriHelper::isUrl($routeStr) ) {
            return $routeStr . '?' . $param;
        }

        return false;
    }

    /**
     * 创建相对路径的url地址
     * @param string $route 'user/login'
     * @param string $params
     * @param string $suffix
     * @param string $mode
     * @return bool|string
     */
    static public function make($route='', $params='', $suffix='', $mode='')
    {
        /**
         * @var $owner $this
         */
        $owner = Ioc::get('uri');

        return $owner->create($route, $params, false, $suffix, $mode);
    }

    /**
     * 创建相对路径的url地址
     * @param string $route 'user/login'
     * @param string $params
     * @param string $suffix
     * @param string $mode
     * @return bool|string
     */
    static public function to($route='', $params='', $suffix='', $mode='')
    {
        /**
         * @var $owner $this
         */
        $owner = Ioc::get('uri');

        return $owner->create($route, $params, false, $suffix, $mode);
    }

    /**
     * 创建绝对路径的url地址
     * @param string $route
     * @param string $params
     * @param string $suffix
     * @param string $mode
     * @return mixed|string
     */
    static public function abs($route='', $params='', $suffix='', $mode='')
    {
        /**
         * @var $owner $this
         */
        $owner = Ioc::get('uri');

        return $owner->create($route, $params, true, $suffix, $mode);
    }

    /*
     * 操作成功后跳转
     */
    public function successJump($url, array $options=[])
    {
        if ( !isset($options['viewFile']) ) {
            $options['viewFile'] = Ulue::$app->get('pages.done_jump');
        }

        $this->getJumpPageData($url, $options);
    }

    public function doneJump($url, array $options=[])
    {
        $this->successJump($url, $options);
    }

    /*
     * 操作失败后跳转，@see successJump()
     */
    public function errorJump($url, array $options=[])
    {
        if ( !isset($options['viewFile']) ) {
            $options['viewFile'] = Ulue::$app->get('pages.error_jump');
        }

        $this->getJumpPageData($url, $options);
    }

    /**
     * [getJumpPageData 带提示的跳转]
     * @param $url string|array   url addr
     * @param  array $options
     * 如果第一个参数是数组，则认为用数组配置传入参数
     * [
     *     'url'       => url addr,
     *     'msg'       => '操作成功',
     *     'time'      => '倒计时',
     *     'btnText'  => '链接信息',
     *     'viewFile' => '视图文件',
     * ]
     * @return void
     */
    protected function getJumpPageData($url, array $options=[])
    {
        $url = $url ? : \Ioc::get('app.uri')->get('index.path');

        $default = [
            'msg'       => '操作成功啦！',
            'time'      => '3',
            'btnText'   => '立即跳转',
            'viewFile'  => Ulue::$app->get('pages.done_jump'),
        ];

        $uriService = \Ioc::get('app.url');
        $url        = $uriService::to($url);
        $options    = array_merge($default, array_filter($options));
        $viewFile   = $options['viewFile'];
        $viewFile   = Ulue::resolveAlias($viewFile);

        if ($options['time'] == 0) {
            header('location:'.$url);
        }

        if (!file_exists($viewFile)) {
            \Trigger::error('文件：'.$viewFile.'不存在，请设置并检查跳转需要的视图文件！');
        }

        $options['url'] = $url;
        unset($options['viewFile']);

        list($msg , $time , $btnText) = array_values( $options );

        include( $viewFile );
        \Ulue::quit();
    }

}// end class Uri